Imports Iou = System.IO
Imports Reg = System.Text.RegularExpressions
Imports Sys = System
Imports Tex = System.Text

Namespace Enhancements.Core.Logging
    ''' <summary>A logging writer implementation which targets the file system.</summary>
    Public NotInheritable Class FileSystemWriter
        Inherits Writer

        Private __Stream As Iou.Stream = Nothing
        Private __ConfigurationMultipleFilesWritesCount As Sys.Int64 = 0

        ''' <summary>Initializes a FileSystemWriter instance.</summary>
        ''' <param name="_configuration">Configuration to use by the instance.</param>
        ''' <param name="_formatter">Formatter to use by the instance.</param>
        ''' <param name="_use">Use to use by the instance.</param>
        ''' <exception cref="IsDisposedException">The instance has been disposed.</exception>
        ''' <exception cref="IsNullException">_configuration is null, or _formatter is null.</exception>
        ''' <exception cref="IsOfTypeNotException">_configuration is not of type FileSystemWriterConfigurationSingleFile or FileSystemWriterConfigurationMultipleFiles.</exception>
        Public Sub New(ByVal _configuration As WriterConfiguration, ByVal _formatter As Formatter, ByVal _use As System.Boolean)
            Configuration = _configuration
            Formatter = _formatter
            Use = _use
        End Sub

        ''' <summary>Gets the configuration used by the instance.</summary>
        ''' <exception cref="IsDisposedException">The instance has been disposed.</exception>
        Public Overrides Property Configuration() As WriterConfiguration
            Get
                ___Assert.___IsDisposedNot("FileSystemWriter[instance]", Me.___DisposeCalled, True)

                Return MyBase.Configuration
            End Get
            Protected Friend Set(ByVal _value As WriterConfiguration)
                ___Assert.___IsDisposedNot("FileSystemWriter[instance]", Me.___DisposeCalled, True)
                ___Assert.___IsNullNot("Configuration._value", _value, True)
                ___Assert.___IsOfType("Configuration._value", _value, New Sys.Type() {GetType(FileSystemWriterConfigurationSingleFile), GetType(FileSystemWriterConfigurationMultipleFiles)}, True)

                MyBase.Configuration = _value
            End Set
        End Property

        ''' <summary>Gets the formatter used by the instance.</summary>
        ''' <exception cref="IsDisposedException">The instance has been disposed.</exception>
        Public Overrides Property Formatter() As Formatter
            Get
                ___Assert.___IsDisposedNot("FileSystemWriter[instance]", Me.___DisposeCalled, True)

                Return MyBase.Formatter
            End Get
            Protected Friend Set(ByVal _value As Formatter)
                ___Assert.___IsDisposedNot("FileSystemWriter[instance]", Me.___DisposeCalled, True)
                ___Assert.___IsNullNot("Formatter._value", _value, True)

                MyBase.Formatter = _value
            End Set
        End Property

        ''' <summary>Gets and sets the value that defines whether the instance should be considered enabled for logging operations.</summary>
        ''' <exception cref="IsDisposedException">The instance has been disposed.</exception>
        Public Overrides Property Use() As System.Boolean
            Get
                ___Assert.___IsDisposedNot("FileSystemWriter[instance]", Me.___DisposeCalled, True)

                Return __Use
            End Get
            Set(ByVal _value As System.Boolean)
                ___Assert.___IsDisposedNot("FileSystemWriter[instance]", Me.___DisposeCalled, True)

                __Use = _value

                If ___Assert.___IsTrueNot("Use", __Use, False) Then
                    If ___Assert.___IsNullNot("__Stream", __Stream, False) Then
                        __Stream.Flush()
                        __Stream.Dispose()
                        __Stream = Nothing
                    End If
                End If
            End Set
        End Property

        Friend Overrides Sub ___Write(ByVal _record As ___Record)
            ___Assert.___IsDisposedNot("FileSystemWriter[instance]", Me.___DisposeCalled, True)
            ___Assert.___IsNullNot("_record", _record, True)
            ___Assert.___IsEmptyNot("_record.___UnformattedIdentifier", _record.___UnformattedIdentifier, True)
            ___Assert.___IsNullNot("_record.___UnformattedCallingProcedure", _record.___UnformattedCallingProcedure, True)
            ___Assert.___IsNullNot("_record.___UnformattedObjects", _record.___UnformattedObjects, True)

            If ___Assert.___IsTrue("Use", Use, False) Then
                __Delete()
                __Create()
                __Format(_record)
                __Write(_record)
            End If
        End Sub

        Private __DeleteCalled As System.Boolean = False
        Private Sub __Delete()
            If ___Assert.___IsTrueNot("__DeleteCalled", __DeleteCalled, False) Then
                __DeleteCalled = True

                If ___Assert.___IsTrue("Configuration.DeleteOnStartup", CType(Configuration, FileSystemWriterConfiguration).DeleteOnStartup, False) Then
                    If ___Assert.___IsOfType("Configuration", Configuration, GetType(FileSystemWriterConfigurationSingleFile), False) Then
                        __DeleteSingleFile()
                    Else
                        If ___Assert.___IsOfType("Configuration", Configuration, GetType(FileSystemWriterConfigurationMultipleFiles), False) Then
                            __DeleteMultipleFiles()
                        End If
                    End If
                End If
            End If
        End Sub

        Private Sub __DeleteSingleFile()
            Dim _configuration As FileSystemWriterConfigurationSingleFile = CType(Configuration, FileSystemWriterConfigurationSingleFile)

            Dim _folder As System.String = TokenPath.___ReplaceAllOccurrences(_configuration.Folder)
            Dim _file As System.String = _configuration.File
            Dim _folderFile As System.String = Iou.Path.Combine(_folder, _file)
            ___Assert.___IsFolderExistent("_folder", _folder, True)

            If ___Assert.___IsFileExistent("_folderfile", _folderFile, False) Then
                Iou.File.Delete(_folderFile)
            End If

            ___Assert.___IsFileExistentNot("_folderFile", _folderFile, True)
        End Sub

        Private Sub __DeleteMultipleFiles()
            Dim _configuration As FileSystemWriterConfigurationMultipleFiles = CType(Configuration, FileSystemWriterConfigurationMultipleFiles)

            Dim _folder As System.String = TokenPath.___ReplaceAllOccurrences(_configuration.Folder)
            ___Assert.___IsFolderExistent("_folder", _folder, True)

            Dim _folderFiles() As System.String = Iou.Directory.GetFiles(_folder, "*", IO.SearchOption.TopDirectoryOnly)
            For Each _folderFile As System.String In _folderFiles
                Dim _file As System.String = Iou.Path.GetFileName(_folderFile)
                If ___Assert.___IsInRegularExpression("_file", _file, TokenGenerator.___BuildRegularExpressionFromFinalValue(_configuration.FilePattern), False) Then
                    Iou.File.Delete(_folderFile)
                    ___Assert.___IsFileExistentNot("_folderFile", _folderFile, True)
                End If
            Next _folderFile
        End Sub

        Private Sub __Create()
            If ___Assert.___IsNull("__Stream", __Stream, False) Then
                If ___Assert.___IsOfType("Configuration", Configuration, GetType(FileSystemWriterConfigurationSingleFile), False) Then
                    __CreateSingleFile()
                Else
                    If ___Assert.___IsOfType("Configuration", Configuration, GetType(FileSystemWriterConfigurationMultipleFiles), False) Then
                        __CreateMultipleFiles()
                    End If
                End If
            End If
        End Sub

        Private Sub __CreateSingleFile()
            Dim _configuration As FileSystemWriterConfigurationSingleFile = CType(Configuration, FileSystemWriterConfigurationSingleFile)

            Dim _folder As System.String = TokenPath.___ReplaceAllOccurrences(_configuration.Folder)
            Dim _file As System.String = _configuration.File
            Dim _folderFile As System.String = Iou.Path.Combine(_folder, _file)
            ___Assert.___IsFolderExistent("_folder", _folder, True)

            If ___Assert.___IsFileExistent("_folderfile", _folderFile, False) Then
                __Stream = New Iou.FileStream(_folderFile, Iou.FileMode.Append, IO.FileAccess.Write, IO.FileShare.Read)
            Else
                __Stream = New Iou.FileStream(_folderFile, Iou.FileMode.CreateNew, IO.FileAccess.Write, IO.FileShare.Read)
            End If
        End Sub

        Private Sub __CreateMultipleFiles()
            Dim _configuration As FileSystemWriterConfigurationMultipleFiles = CType(Configuration, FileSystemWriterConfigurationMultipleFiles)

            Dim _folder As System.String = TokenPath.___ReplaceAllOccurrences(_configuration.Folder)
            ___Assert.___IsFolderExistent("_folder", _folder, True)

            Dim _folderFile As System.String = Nothing
            Do
                _folderFile = Iou.Path.Combine(_folder, TokenGenerator.___ReplaceAllOccurrencesWithNewValues(_configuration.FilePattern))
            Loop Until ___Assert.___IsFileExistentNot("_folderfile", _folderFile, False)
            __Stream = New Iou.FileStream(_folderFile, Iou.FileMode.CreateNew, IO.FileAccess.Write, IO.FileShare.Read)
        End Sub

        Private Sub __Format(ByVal _record As ___Record)
            Formatter.___Format(_record)
            ___Assert.___IsNullNot("_record.___Formatted", _record.___Formatted, True)
        End Sub

        Private Sub __Write(ByVal _record As ___Record)
            __Stream.Write(_record.___Formatted, 0, _record.___Formatted.Length)

            If ___Assert.___IsOfType("Configuration", Configuration, GetType(FileSystemWriterConfigurationMultipleFiles), False) Then
                Dim _configuration As FileSystemWriterConfigurationMultipleFiles = CType(Configuration, FileSystemWriterConfigurationMultipleFiles)
                Dim _disposeStream As System.Boolean = False

                __ConfigurationMultipleFilesWritesCount += 1
                If ___Assert.___IsInRange("__ConfigurationMultipleFilesWritesCount", __ConfigurationMultipleFilesWritesCount, _configuration.NewFileCreationCriteriaWritesCount, Sys.Int64.MaxValue, False) Then
                    _disposeStream = True
                    __ConfigurationMultipleFilesWritesCount = 0
                End If
                If ___Assert.___IsInRange("__Stream.Length", __Stream.Length, _configuration.NewFileCreationCriteriaBytesCount, Sys.Int64.MaxValue, False) Then
                    _disposeStream = True
                End If

                If ___Assert.___IsTrue("_disposeStream", _disposeStream, False) Then
                    __Stream.Flush()
                    __Stream.Dispose()
                    __Stream = Nothing
                End If
            End If
        End Sub

        Friend Overrides Sub ___Dispose()
            ___Assert.___IsDisposedNot("FileSystemWriter[instance]", Me.___DisposeCalled, True)
            ___DisposeCalled = True

            If ___Assert.___IsNullNot("__Stream", __Stream, False) Then
                __Stream.Flush()
                __Stream.Dispose()
                __Stream = Nothing
            End If
        End Sub

    End Class
End Namespace
